home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / thinkref / archive / THINKPascal4.0.2Update.sea.hqx / THINK Pascal 4.0.2 Update / Misc Updates.sea / THINK Pascal 4.0 Folder / UMemory.p < prev   
Text File  |  1992-06-16  |  62KB  |  2,207 lines

  1. {    This file has been processed by The THINK Pascal Source Converter, v1.1.2.    }
  2.  
  3. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n+]}
  4. { UMemory.p }
  5. { Copyright © 1984-1990  Apple Computer, Inc.  All rights reserved. }
  6.  
  7. {$IFC UNDEFINED UsingIncludes}
  8. {$SETC UsingIncludes := FALSE}
  9. {$ENDC}
  10.  
  11. unit UMemory;
  12.  
  13. interface
  14.  
  15.     uses
  16.         SysEqu, Traps, ULoMem, 
  17. {$SETC __UMemory__ := TRUE}
  18. { • MacApp }
  19.         UMacAppUtilities, UFailure,
  20. { • Required for this unit's interface }
  21.  
  22. { • Implementation use }
  23.         UPatch, 
  24.  
  25.         UDebug;
  26.  
  27.  
  28.             { • Include the public interface }
  29.  
  30.  
  31.  
  32. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  33. { UMemory.p }
  34. { Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. }
  35.  
  36. {[f-]}
  37. {}
  38. {    This unit implements MacApp's memory management and segment management}
  39. {    schemes.}
  40. {}
  41. {    The memory management scheme works by distinguishing between "permanent"}
  42. {    and "temporary" heap allocation requests.    Permanent requests are}
  43. {    typically used for data your application allocates:  objects and}
  44. {    handles.  Temporary requests are used for code segments and Toolbox}
  45. {    resources and data, such as WDEF's and CDEF's.}
  46. {}
  47. {    Permanent memory objects are considered permanent because they}
  48. {    are not purged from memory until you explicitly dispose of or free them.}
  49. {    (Of course, the Macintosh Memory Manager will purge them if they're}
  50. {    marked purgeable.)    Permanent objects are allocated with NewPermHandle.}
  51. {    This prevents the MacApp GrowZone from purging temporary objects to}
  52. {    accommodate a permanent one.  In MacApp, all TObjects and its descendants}
  53. {    are considered permanent, and are allocated with NewPermHandle.}
  54. {}
  55. {    Temporary memory objects are considered temporary because MacApp's}
  56. {    GrowZone procedure may purge them from memory to satisfy a memory}
  57. {    allocation request.  This is true regardless of whether the object is}
  58. {    marked non-purgeable, although the GrowZone procedure will not purge}
  59. {    locked objects (such as code segments in use).    Typically, temporary}
  60. {    objects are marked non-purgeable so that MacApp's GrowZone can control}
  61. {    when they are purged.}
  62. {}
  63. {    MacApp reserves a specific amount of heap space for temporary objects,}
  64. {    the idea being that the space reserved is large enough to handle the}
  65. {    largest number of temporary objects (e.g. code and system resources)}
  66. {    needed at any given time.    If this amount is sufficiently large, your}
  67. {    program will never fail loading a segment or system resource.    This}
  68. {    amount is defined by the internal variable pSzCodeReserve.    You can}
  69. {    retrieve its value by calling GetReserveSize.    It is initially set by}
  70. {    the 'seg!' and 'mem!' resources, and can be changed at run-time by}
  71. {    calling SetReserveSize.  The procedure BuildCodeReserve reserves the}
  72. {    space by allocating the handle pCodeReserve and setting its size to}
  73. {    pSzCodeReserve - (the total size of all temporary objects in memory}
  74. {    [at that time]).}
  75. {}
  76. {    When a temporary object is loaded into memory, the size of pCodeReserve}
  77. {    is adjusted accordingly. Permanent objects can be loaded into memory}
  78. {    only so long as there will still be at least pSzCodeReserve bytes}
  79. {    available for temporary objects.}
  80. {}
  81. {    To identify which objects in the heap are temporary, MacApp maintains}
  82. {    four lists of handles.    The objects identified by these handles are}
  83. {    considered temporary and fall under the control of MacApp's GrowZone}
  84. {    procedure.    The lists are:}
  85. {}
  86. {    gCodeSegs - A list of handles to all CODE resources in the application}
  87. {    and system resource forks.}
  88. {}
  89. {    gSysMemList - A list handles to RAM-based system resources.}
  90. {    By default this list includes all PACK, LDEF, MDEF, CDEF and WDEF}
  91. {    resources in the system and application resource forks. You can add}
  92. {    other resources, such as fonts, by calling AddHandle.}
  93. {}
  94. {    gApp1MemList, gApp2MemList - Lists of handles to application data or}
  95. {    resources.    MacApp initializes both lists to NIL.  The difference}
  96. {    between the two lists is that handles in gApp1MemList are purged}
  97. {    before those in gApp2MemList.  You may add your own handles to these}
  98. {    lists by allocating them with NewHandle and calling AddHandle for each}
  99. {    handle to be added to the list.}
  100. {}
  101. {    The Macintosh Memory Manager calls MacApp's GrowZone procedure only when}
  102. {    all purgeable objects have been purged from the heap and there is still}
  103. {    insufficient space to satisfy a memory request.  The GrowZone will}
  104. {    look through the lists of temporary objects in memory, making one}
  105. {    purgeable so long as there is still at least pSzCodeReserve bytes}
  106. {    allocated to temporary memory (the total size of the temporary objects}
  107. {    in memory and the pCodeReserve handle).  The GrowZone procedure attempts}
  108. {    to never allow the size of the temporary objects and reserve to fall}
  109. {    below pSzCodeReserve, thereby guaranteeing that space is always avail-}
  110. {    able for code segments and system resources (provided pSzCodeReserve is}
  111. {    large enough to handle your application at its most memory intensive}
  112. {    state).}
  113. {}
  114. {    The value of pSzCodeReserve is determined at startup-time by adding up}
  115. {    the size of all the segments named in the 'seg!' resources, and adding}
  116. {    the first value of each of the 'mem!' resources.  You can derive these}
  117. {    resources by observing your program and using the MacApp debugger to}
  118. {    help you determine when your application uses the largest amount of}
  119. {    code and system resources.    Typically, we've found that this happens}
  120. {    while printing on the LaserWriter, or during initialization or term-}
  121. {    ination.}
  122. {}
  123. {    MacApp maintains another reserve, known as the low memory reserve.}
  124. {    This is a kind of emergency reserve--when all else fails we release}
  125. {    the pMemReserve handle.  Its size is initially determined by the second}
  126. {    number of each 'mem!' resource, and can be changed by calling}
  127. {    SetReserveSize.  You can retrieve its size by calling GetReserveSize.}
  128. {    Internally, the low-memory reserve is allocated with the pMemReserve}
  129. {    handle, and its size is stored in pSzMemReserve.}
  130. {}
  131. {    The procedure InitUMemory is responsible for initially setting up the}
  132. {    temporary and low-memory reserves, setting up the GrowZone procedure,}
  133. {    initializing handle lists, and patching LoadSeg.  It signals failure}
  134. {    if the temporary reserve could not be allocated.}
  135. {}
  136. {[f+]}
  137.  
  138. {$IFC UNDEFINED UsingIncludes}
  139. {$SETC UsingIncludes := FALSE}
  140. {$ENDC}
  141.  
  142.  
  143.  
  144.  
  145.  
  146.  
  147.  
  148.  
  149.         { • Auto-Include the requirements for this unit's interface. }
  150.  
  151.  
  152.  
  153.  
  154.  
  155.  
  156.  
  157.  
  158.     const
  159.         kGZMaxAlloc = $7FFFFFFF;
  160.         kCode = 'CODE';                { Resource type for code }
  161.  
  162.     type
  163.  
  164.         AHandleList = array[1..5000] of Handle; { A list of handles }
  165.         HandleListPtr = ^AHandleList;         { Preferred }
  166.         HandleListHandle = ^HandleListPtr;        { Preferred }
  167.         PHandleList = HandleListPtr;        { Left in for compatibility (2.0) }
  168.         HHandleList = HandleListHandle;     { Left in for compatibility (2.0) }
  169.  
  170.         ABoolList = array[1..5000] of BOOLEAN; { A list of BOOLEAN }
  171.         BoolListPtr = ^ABoolList;
  172.         BoolListHandle = ^BoolListPtr;
  173.  
  174.         ALongList = array[1..5000] of LONGINT; { A list of LONGINT }
  175.         LongListPtr = ^ALongList;
  176.         LongListHandle = ^LongListPtr;
  177.  
  178.     var
  179.         gMaxLockedRsrc: Size;                    { The maximum memory consumed by locked}
  180. {                                                         resources. See CheckRsrcUsage procedure.}
  181.             {$IFC qDebug}
  182.         gMemMgtBreak: BOOLEAN;                { if TRUE, break into debugger rather than}
  183. {                                                         just report memory mgt. information}
  184.         gRsrcReport: BOOLEAN;                { Report resource maximums to the debugger}
  185. {                                                         window.}
  186.         gSegReport: BOOLEAN;                { Report segment loadings to the debugger}
  187. {                                                         window.}
  188.             {$ENDC}
  189.         gSysMemList: HandleListHandle;        { List of system handles used to compute}
  190. {                                                         current allocated temporary memory (all}
  191. {                                                         PACK, LDEF, MDEF, CDEF, WDEF resources).}
  192. {                                                         See ScanHandles procedure.}
  193.         gApp1MemList,                                { an application defined memlist }
  194.         gApp2MemList: HandleListHandle;        { These start out NIL. You can create lists}
  195. {                                                         of handles and place then in either of}
  196. {                                                         these variables. (One list might be}
  197. {                                                         permanent handles in your application, and}
  198. {                                                         the other based on the current situation.)}
  199. {                                                         The values stored here should be a handle}
  200. {                                                         to a list of other handles. If you modify}
  201. {                                                         either of these lists, call CheckReserve.}
  202. {                                                         It calls BuildAllReserves to recompute the}
  203. {                                                         code and low space reserve. CheckReserve's}
  204. {                                                         result indicates whether the full code}
  205. {                                                         reserve is present. If not, then your}
  206. {                                                         program may crash because a segment (or}
  207. {                                                         defproc) can't be loaded. The handles in}
  208. {                                                         the lists should normally be resources}
  209. {                                                         that your application might require at any}
  210. {                                                         given time. All these handles will}
  211. {                                                         normally be marked non-purgeable. The}
  212. {                                                         GrowZone proc, however, can purge any of}
  213. {                                                         these handles that are not locked.}
  214.  
  215.         gCodeRefNum: INTEGER;                { Reference to where to find code segements}
  216. {}
  217.  
  218.         gCodeSegs: HandleListHandle;        { List of all code segments }
  219.         gIsLoadedSeg: BoolListHandle;            { Maintains a flag for each segment,}
  220. {                                                         indicating whether the segment is loaded (in the}
  221. {                                                         segment loader sense).  Thereby optimizing}
  222. {                                                         UnloadAllSegments.}
  223.         gIsResidentSeg: BoolListHandle;            { Maintains a flag for each segment,}
  224. {                                                         indicating whether the segment is resident}
  225. {                                                         and hence should not be unloaded (in the}
  226. {                                                         segment loader sense).}
  227.  
  228.         gUnloadAllSegs: BOOLEAN;                { UnloadAllSegments doesn't unload segments}
  229. {                                                        if this flag is false.}
  230.  
  231.         gGZPurgeNotify: ProcPtr;                { If non-NIL, then this will be called}
  232. {                                                         before the Grow Zone proc purges a handle.}
  233. {                                                         The proc will be passed the actual handle.}
  234. {}
  235.             { These are meant to be private but are in the interface just in case. }
  236.         pSegSize: LongListHandle;            { Maintains size of each code resource. }
  237.  
  238.         pCodeReserve: Handle;                 { Allocates temporary (code) reserve. }
  239.         pMemReserve: Handle;                 { Allocates low memory reserve. }
  240.         pOKCodeReserve: BOOLEAN;                { if TRUE then we have an adequate code}
  241. {                                                         reserve; if FALSE then the application}
  242. {                                                         could crash if memory is tight}
  243.         pPermAllocation: BOOLEAN;
  244.         pReserveExists: BOOLEAN;                { TRUE if the code reserve is known to be}
  245. {                                                         fully allocated}
  246.             {$IFC qDebug}
  247.         pReserveShortfall: LONGINT;                { amt. that we are lacking in the code}
  248. {                                                         reserve}
  249.             {$ENDC}
  250.         pSzCodeReserve: Size;                    { Attempt to reserve this much memory for}
  251. {                                                         the temporary (code) reserve.}
  252.         pSzMemReserve: Size;                    { Attempt to reserve this much memory for}
  253. {                                                         the low-memory reserve.}
  254.  
  255.         pSegLoadPatch: TrapPatch;                { patch for LoadSeg }
  256.  
  257.         pOldResFile: INTEGER;                { The res file reference saved across}
  258. {                                                         segloads}
  259.         pLoadSegCalledFromOwnApp: BOOLEAN;            { TRUE if calling LoadMacAppSeg from the app}
  260. {                                                         and not from a _DA_ in our own heap.}
  261. {                                                         (wheels within wheels for Pete's sake!)}
  262.  
  263.         pMaxSegNum: INTEGER;                { The maximum segment number }
  264.  
  265.             { I N I T I A L I Z A T I O N }
  266.  
  267.     procedure InitUMemory;
  268.         { Initializes this unit. Must be called before using this unit. The caller must be in the}
  269. {        program's main segment. Sets up the gCodeSegs and gSysMemList handle lists, sets the grow}
  270. {        zone, calls MaxApplZone, sets gApp1MemList and gApp2MemList to NIL, patches LoadSeg and}
  271. {        allocates the temporary and low-memory reserves. Fails if unable to allocate the temporary}
  272. {        reserve.}
  273.  
  274.         { S E G M E N T   L O A D I N G }
  275.  
  276.         { DEBUGGING NOTE: You cannot set a MacApp breakpoint at any of these}
  277. {        routines, because they must not call anything (eg. %_BP) that may}
  278. {        require a segment load.}
  279.  
  280.     function GetSegNumber (aProc: ProcPtr): INTEGER;
  281.         { GetSegNumber returns the number of the segment in which aProc resides. }
  282.  
  283.     function GetSegFromPC (ppc: LONGINT): INTEGER;
  284.         { Given a pc pointer, return the segment number or 0 if not found.}
  285. {        Must be a loaded code segment.}
  286.  
  287.     function GetSegSize (segnum: INTEGER): Size;
  288.         { GetSegSize returns the size, in bytes, of the segment whose number is segnum. }
  289.  
  290.     function LoadMacAppSegment (segnum: INTEGER): LONGINT;
  291.         { This function patches LoadSeg. It is called from the assembly-language routine}
  292. {        AMacAppLoadSeg, which is the actual patch setup by PatchTrap. AMacAppLoadSeg saves}
  293. {        registers and sets up the stack by 1) allocating space for LoadMacAppSegment's result,}
  294. {        and 2) pushing a copy of LoadSeg's parameter onto the stack for use by LoadMacAppSegment.}
  295. {        Signals failure if the segment could not be loaded.}
  296.  
  297.     procedure LoadResidentSegments;
  298.         { Makes resident the segments whose names are included in any 'res!' resources. }
  299.  
  300.     function PreloadSegment (segnum: INTEGER): BOOLEAN;
  301.         { PreloadSegment calls PreloadSegmentResource to load a segment in the resource manager}
  302. {        sense and then calls the segment loader to load it in the segment loader sense.}
  303.  
  304.     function PreloadSegmentResource (segnum: INTEGER): BOOLEAN;
  305.         { PreloadSegment is available to programmers who want to lock a segment at the top of the}
  306. {        heap without having to call a dummy procedure in that segment. It is also useful for}
  307. {        determining whether a segment can in fact be loaded before you try to execute code in it.}
  308. {        PreloadSegment returns TRUE if the segment could be loaded, false otherwise.}
  309.  
  310.     procedure SetResidentSegment (segnum: INTEGER; makeResident: BOOLEAN);
  311.         { SetResidentSegment can be used to make a segment resident (or no longer resident); resident}
  312. {        segments will not be unloaded by UnloadAllSegments; if a segment is made resident, it is}
  313. {        also preloaded.MacApp® automatically marks its resident segment as resident (the one}
  314. {        containing the procedure CmdFromMenuItem); you probably should do UnloadAllSegments before}
  315. {        making a segment resident, to ensure that it is locked at the top of the heap.}
  316.  
  317.     procedure UnloadAllSegments;
  318.         { UnloadAllSegments unloads all segments except the blank segment or the ones marked}
  319. {        resident. It is called at each iteration of the main event loop to compact memory, as well}
  320. {        as other places where compacting memory is needed or desirable.}
  321.  
  322.         { H A N D L E L I S T    M A N A G E M E N T }
  323.  
  324.     procedure AddHandle (h: Handle; toList: HandleListHandle);
  325.         { Adds a handle to the list of handles; does not check if the handle already exists in the}
  326. {        list. Simply calls Munger to add to the front of the list.}
  327.  
  328.     procedure AddAllRsrc (rType: ResType; toList: HandleListHandle);
  329.         { Adds all the resources of type rType to the list. Filters out all ROM resources.Calls}
  330. {        AddHandle.}
  331.  
  332.     procedure RemHandle (h: Handle; toList: HandleListHandle);
  333.         { Removes the handle from list. }
  334.  
  335.     procedure ScanHandles (procedure DoToHandle (h: Handle));
  336.         { Calls DoToHandle for each handle in the lists gCodeSegs, gSysMemList, gApp1MemList and}
  337. {        gApp2MemList. This procedure assumes that DoToHandle does not compact memory.}
  338.  
  339.         { M E M O R Y M A N A G E M E N T }
  340.  
  341.     procedure BuildAllReserves;
  342.         { BuildAllReserves creates the code (temporary memory) and low space reserves. These are kept}
  343. {        for use at a time when an out-of-memory condition has occurred to allow most such}
  344. {        occurrances to recover smoothly by deallocating the space.}
  345.  
  346.     function CheckReserve: BOOLEAN;
  347.         { Checks to see if the code reserve is OK. Calls BuildAllReserves and returns true if the}
  348. {        full code reserve is present. If this returns false your application may bomb because a}
  349. {        segment or system resource can't be loaded.}
  350.  
  351.         {$IFC qDebug}
  352.  
  353.     procedure CheckRsrcUsage;
  354.         { Checks to see if the total size of the currently loaded resources exceeds the maximum}
  355. {        (gMaxLockedRsrc).If so, the new maximum is set.If gRsrcReport is true, then the new maximum}
  356. {        is reported in the debugger window.If gMemMgtBreak then program execution is stopped.}
  357.         {$ENDC qDebug}
  358.  
  359.         {$IFC qDebug}
  360.  
  361.     procedure DoChangeReserve (alter: BOOLEAN; var codeReserve, codeShort, lowSpaceReserve: Size; var gotCode, gotLowSpace: BOOLEAN);
  362.         { Called by the MacApp® debugger to change the reserve allocation. Not normally called by an}
  363. {        application.}
  364.         {$ENDC qDebug}
  365.  
  366.     procedure FailNoReserve;
  367.         { IF NOT CheckReserve THEN Failure(memFullErr, 0). }
  368.  
  369.     procedure FailSpaceIsLow;
  370.         { IF MemSpaceIsLow THEN Failure(memFullErr, 0). }
  371.  
  372.     procedure GetReserveSize (var szCodeReserve, szMemReserve: Size);
  373.         { Returns the amount of memory that is to be reserved for the code and memory reserve. This}
  374. {        is not a true indication of whether this amount of memory has in fact been reserved. Call}
  375. {        CheckReserve to find out if the code reserve could be allocated, and call MemSpaceIsLow to}
  376. {        find out if the low-memory reserve could be allocated.}
  377.  
  378.     function MemSpaceIsLow: BOOLEAN;
  379.         { Returns TRUE if the low space reserve is missing. }
  380.  
  381.     function NewPermPtr (logicalSize: Size): Ptr;
  382.         { Allocates a permanent Pointer; you should call this instead of NewPointer if allocating}
  383. {        some permanent memory.}
  384.  
  385.     function NewPermHandle (logicalSize: Size): Handle;
  386.         { Allocates a permanent handle; you should call this instead of NewHandle if allocating some}
  387. {        permanent memory.}
  388.  
  389.     function PermAllocation (permanent: BOOLEAN): BOOLEAN;
  390.         { PermAllocation controls whether subsequent memory allocations are considered permanent or}
  391. {        temporary.Pass TRUE to setup things for a permanent allocation.Returns the previous state}
  392. {        of the permanent flag.}
  393.  
  394.     procedure SetPermHandleSize (h: Handle; newSize: Size);
  395.         { Use this call to size permanent handles. It sets/resets the permanent flag correctly and}
  396. {        does a FailMemError.}
  397.  
  398.     procedure SetPermPtrSize (p: Ptr; newSize: Size);
  399.         { Use this call to size permanent pointers. It sets/resets the permanent flag correctly and}
  400. {        does a FailMemError.}
  401.  
  402.     procedure SetReserveSize (forCode, forOther: Size);
  403.         { Call this to set the size of the memory reserved for code (temporary) and permanent (low}
  404. {        memory) requests.}
  405.  
  406.     function TotalTempSize (justLocked: BOOLEAN; var canPurge: Handle): Size;
  407.         { TotalTempSize returns the total number of bytes of the temporary handles currently in RAM}
  408. {        (or only locked/in use handles if justLocked is TRUE).  CanPurge is set to an unlocked}
  409. {        handle that can be purged if desired.  Uses ScanHandles.}
  410.  
  411.         {$IFC qDebug}
  412.  
  413.     procedure WriteReserves;
  414.         { WRITELN's the temporary reserve and low-memory reserves in the debug window. }
  415.         {$ENDC}
  416.  
  417.         { U T I L I T I E S }
  418.  
  419.     function AddSegSizes (segRsrc: Handle): Size;
  420.         { Returns the total size of the code segments whose names are in the string list segRrsc. }
  421.  
  422.     procedure SetStackSpace (numBytes: Size);
  423.         { Set the stack space to at least numBytes. }
  424.  
  425.  
  426.     procedure WithCodeResFileDo (procedure DoWithResFile);
  427.         { Ensure that the resource call is done against gCodeRefNum }
  428.  
  429.  
  430.  
  431.  
  432. implementation
  433.  
  434.  
  435. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  436. { UMemory.inc1.p }
  437. { Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. }
  438.  
  439.  
  440.  
  441. {$R-}
  442.  
  443. {$V-}
  444.  
  445.  
  446.     var
  447.         pDuringGrowZone: BOOLEAN;
  448.  
  449.     function GrowZoneProc (needed: Size): LONGINT;
  450.     FORWARD;
  451.  
  452.     procedure BuildCodeReserve (allocLim: Size; fromGZ: BOOLEAN);
  453.     FORWARD;
  454.  
  455.     function HandleIsEligible (h: Handle): BOOLEAN;
  456.     FORWARD;
  457.  
  458. {--------------------------------------------------------------------------------------------------}
  459.  
  460.     procedure ALoadMacAppSeg;
  461.     EXTERNAL;
  462.  
  463.     procedure APostLoadMacAppSeg;
  464.     EXTERNAL;
  465.  { LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls}
  466. {  LoadMacAppSegment. ALoadMacAppSeg can only be referenced as a}
  467. {  procedure pointer, because no args are declared}
  468.  
  469.     procedure EachFrameDo (calleeFrame, ppc: LONGINT; procedure DoToFrame (calleeFrame: LONGINT; ppc: LONGINT; callerFrame: LONGINT; itsFrame: LONGINT));
  470.     EXTERNAL;
  471.  
  472.     function PreloadSegment (segNum: INTEGER): BOOLEAN;
  473.     EXTERNAL;
  474.  
  475.     procedure CallNotify (h: Handle; routine: ProcPtr);
  476.     inline
  477.         $205F, $4E90;                                { MOVE.L (A7)+,A0; JSR (A0) }
  478.  
  479. {--------------------------------------------------------------------------------------------------}
  480.  
  481.     {}
  482. {    These "MAFoo" functions are primarily for THINK™ Pascal compatibility (but useful in the larger}
  483. {    problem of multiple open resource maps in general); when running under the THINK™ environment,}
  484. {    CODE resources are not found in the same resource file as other application resources, so a}
  485. {    UseResFile call needs to be made to bring the project resource file into the search path.}
  486. {    "gCodeRefNum" is set up at initialization time.}
  487. {    !!! A much more general solution to "the resource problem" appears to be warranted.}
  488. {}
  489.  
  490. {--------------------------------------------------------------------------------------------------}
  491. {$S MAMemoryRes}
  492.  
  493.     function MAGet1Resource (rType: ResType; rID: INTEGER): Handle;
  494.  
  495.         var
  496.             oldResFile: INTEGER;
  497.  
  498.     begin
  499.         oldResFile := MAUseResFile(gCodeRefNum);
  500.         MAGet1Resource := Get1Resource(rType, rID);
  501.         if MAUseResFile(oldResFile) <> 0 then
  502.             ;
  503.     end;
  504.  
  505. {--------------------------------------------------------------------------------------------------}
  506. {$S MAMemoryRes}
  507.  
  508.     function MAGet1NamedResource (rType: ResType; name: Str255): Handle;
  509.  
  510.         var
  511.             oldResFile: INTEGER;
  512.  
  513.     begin
  514.         oldResFile := MAUseResFile(gCodeRefNum);
  515.         MAGet1NamedResource := Get1NamedResource(rType, name);
  516.         if MAUseResFile(oldResFile) <> 0 then
  517.             ;
  518.     end;
  519.  
  520. {--------------------------------------------------------------------------------------------------}
  521. {$S MAMemoryRes}
  522.  
  523.     function MAGet1IndResource (rType: ResType; index: INTEGER): Handle;
  524.  
  525.         var
  526.             oldResFile: INTEGER;
  527.  
  528.     begin
  529.         oldResFile := MAUseResFile(gCodeRefNum);
  530.         MAGet1IndResource := Get1IndResource(rType, index);
  531.         if MAUseResFile(oldResFile) <> 0 then
  532.             ;
  533.     end;
  534.  
  535. {--------------------------------------------------------------------------------------------------}
  536. {$S MAMemoryRes}
  537.  
  538.     function MACount1Resources (rType: ResType): INTEGER;
  539.  
  540.         var
  541.             oldResFile: INTEGER;
  542.  
  543.     begin
  544.         oldResFile := MAUseResFile(gCodeRefNum);
  545.         MACount1Resources := Count1Resources(rType);
  546.         if MAUseResFile(oldResFile) <> 0 then
  547.             ;
  548.     end;
  549.  
  550. {--------------------------------------------------------------------------------------------------}
  551. {$S MAMemoryRes}
  552.  
  553.     function MAGetResource (rType: ResType; rID: INTEGER): Handle;
  554.  
  555.         var
  556.             h: Handle;
  557.             oldResFile: INTEGER;
  558.  
  559.     begin
  560.         oldResFile := MAUseResFile(gCodeRefNum);
  561.         h := GetResource(rType, rID);
  562.         if MAUseResFile(oldResFile) <> 0 then
  563.             ;
  564.  
  565.         if HomeResFile(h) <> gCodeRefNum then
  566.             h := nil;
  567.  
  568.         MAGetResource := h;
  569.     end;
  570.  
  571. {--------------------------------------------------------------------------------------------------}
  572. {$S MAMemoryRes}
  573.  
  574.     function MAGetNamedResource (rType: ResType; name: Str255): Handle;
  575.  
  576.         var
  577.             h: Handle;
  578.             oldResFile: INTEGER;
  579.  
  580.     begin
  581.         oldResFile := MAUseResFile(gCodeRefNum);
  582.         h := GetNamedResource(rType, name);
  583.         if MAUseResFile(oldResFile) <> 0 then
  584.             ;
  585.  
  586.         if HomeResFile(h) <> gCodeRefNum then
  587.             h := nil;
  588.  
  589.         MAGetNamedResource := h;
  590.     end;
  591.  
  592. {--------------------------------------------------------------------------------------------------}
  593. {$S MAMemoryRes}
  594.  
  595.     function MAGetIndResource (rType: ResType; index: INTEGER): Handle;
  596.  
  597.         var
  598.             h: Handle;
  599.             oldResFile: INTEGER;
  600.  
  601.     begin
  602.         oldResFile := MAUseResFile(gCodeRefNum);
  603.         h := GetIndResource(rType, index);
  604.         if MAUseResFile(oldResFile) <> 0 then
  605.             ;
  606.  
  607.         if HomeResFile(h) <> gCodeRefNum then
  608.             h := nil;
  609.  
  610.         MAGetIndResource := h;
  611.     end;
  612.  
  613. {--------------------------------------------------------------------------------------------------}
  614. {$S MAMemoryRes}
  615.  
  616.     function MACountResources (rType: ResType): INTEGER;
  617.  
  618.         var
  619.             oldResFile: INTEGER;
  620.  
  621.     begin
  622.         oldResFile := MAUseResFile(gCodeRefNum);
  623.         MACountResources := CountResources(rType);
  624.         if MAUseResFile(oldResFile) <> 0 then
  625.             ;
  626.     end;
  627.  
  628. {--------------------------------------------------------------------------------------------------}
  629. {$S MAMemoryRes}
  630.  
  631.     function GetSegResource (segNum: INTEGER): Handle;
  632.  
  633.     begin
  634.         if qNeedsROM128k | gConfiguration.hasROM128k then
  635.             GetSegResource := MAGet1Resource(kCode, segNum)
  636.         else
  637.             GetSegResource := MAGetResource(kCode, segNum);
  638.     end;
  639.  
  640. {--------------------------------------------------------------------------------------------------}
  641. {$S MAMiniInit}
  642.  
  643.     procedure AddAllRsrc (rType: ResType; toList: HandleListHandle);
  644.  
  645.         var
  646.             oldResLoad: BOOLEAN;
  647.             i: INTEGER;
  648.             h: Handle;
  649.             theID: INTEGER;
  650.             theType: ResType;
  651.             theName: Str255;
  652.  
  653.     begin
  654.         oldResLoad := GetResLoad;
  655.         SetResLoad(FALSE);
  656.  
  657.         for i := 1 to CountResources(rType) do
  658.             begin
  659.                 h := GetIndResource(rType, i);
  660.                 GetResInfo(h, theID, theType, theName);
  661.  
  662.   { If there is a ROM resource for this type and ID, don't put it}
  663. {   on the list.}
  664.                 UseROMMap(FALSE);
  665.                 h := GetResource(rType, theID);
  666.                 UseROMMap(FALSE);
  667.                 if HomeResFile(h) <> 1 then
  668.                     AddHandle(h, toList);
  669.  
  670.             end;
  671.  
  672.         SetResLoad(oldResLoad);
  673.     end;
  674.  
  675. {--------------------------------------------------------------------------------------------------}
  676. {$S MAMiniInit}
  677.  
  678.     procedure AddHandle (h: Handle; toList: HandleListHandle);
  679.  
  680.         var
  681.             offset: LONGINT;
  682.  
  683.     begin
  684.         offset := Munger(Handle(toList), 0, nil, 0, @h, 4);
  685.         FailMemError;
  686.     end;
  687.  
  688. {--------------------------------------------------------------------------------------------------}
  689. {$S MAMiniInit}
  690.  
  691.     function AddSegSizes (segRsrc: Handle): LONGINT;
  692.  
  693.         var
  694.             p: SignedBytePtr;
  695.             oldResLoad: BOOLEAN;
  696.             total: LONGINT;
  697.             seg: Handle;
  698.             i: INTEGER;
  699.             s: Str255;
  700.  
  701.     begin
  702.         LockHandleHigh(segRsrc);
  703.  
  704.         oldResLoad := GetResLoad;
  705.         SetResLoad(FALSE);
  706.  
  707.         p := SignedBytePtr(segRsrc^);
  708.         i := IntegerPtr(p)^;
  709.         p := SignedBytePtr(Ord(p) + 2);
  710.  
  711.         total := 0;
  712.  
  713.         while i > 0 do
  714.             begin
  715.                 BlockMove(Ptr(p), @s, p^ + 1);
  716.  
  717.                 p := SignedBytePtr(Ord(p) + p^ + 1);
  718.                 i := i - 1;
  719.  
  720.                 if qNeedsROM128k | gConfiguration.hasROM128k then
  721.                     seg := MAGet1NamedResource(kCode, s)
  722.                 else
  723.                     seg := MAGetNamedResource(kCode, s);
  724.  
  725.                 if seg <> nil then
  726.                     total := total + SizeResource(seg) + 8;
  727.             end;
  728.  
  729.         AddSegSizes := total;
  730.  
  731.         SetResLoad(oldResLoad);
  732.  
  733.         HUnlock(segRsrc);
  734.     end;
  735.  
  736. {--------------------------------------------------------------------------------------------------}
  737. {$S MAMemoryRes}
  738. {$Push}
  739.  {$IFC qTrace}
  740.  {$N+}
  741.  {$ENDC}
  742.  
  743.     procedure BuildAllReserves;
  744.  
  745.         const
  746.             initVal = $F7;
  747.  
  748.         var
  749.             oldPerm: BOOLEAN;
  750.         {$IFC qDebug}
  751.             theSize: Size;
  752.         {$EndC}
  753.  
  754.     begin
  755.   { set the permanent flag to ensure that the code reserve is}
  756. {   actually allocated and not given up to the low space reserve}
  757.         oldPerm := pPermAllocation;
  758.         pPermAllocation := TRUE;
  759.  
  760.     { make sure code reserve is OK }
  761.         BuildCodeReserve(kGZMaxAlloc, FALSE);
  762.  
  763.     { reallocate the low space handle, if necessary }
  764.         if IsHandlePurged(pMemReserve) then
  765.             begin
  766.  
  767.                 ReallocHandle(pMemReserve, pSzMemReserve);
  768.         {$IFC qDebug}
  769.                 theSize := GetHandleSize(pMemReserve);
  770.         {$Push}
  771.  {$R-}
  772.                 if theSize <> 0 then
  773.                     BlockSet(pMemReserve^, theSize, initVal);
  774.         {$Pop}
  775.         {$EndC}
  776.             end;
  777.  
  778.     { reset the permanent flag }
  779.         pPermAllocation := oldPerm;
  780.     end;
  781. {$Pop}
  782.  
  783. {--------------------------------------------------------------------------------------------------}
  784. {$S MAMemoryRes}
  785. {$Push}
  786.  {$IFC qTrace}
  787.  {$N+}
  788.  {$ENDC}
  789.  
  790.     procedure BuildCodeReserve (allocLim: Size; fromGZ: BOOLEAN);
  791.  
  792.         const
  793.             initVal = $F7;
  794.  
  795.         var
  796.             needed: Size;
  797.             avail: Size;
  798.             canPurge: Handle;
  799.         {$IFC qDebug}
  800.             theSize: Size;
  801.         {$EndC}
  802.  
  803.     begin
  804.         pOKCodeReserve := TRUE;                             { default value }
  805.  
  806.     {$IFC qDebug}
  807.         pReserveShortfall := 0;
  808.  
  809.         if not pPermAllocation then
  810.             ProgramBreak('BuildCodeReserve called with pPermAllocation = FALSE');
  811.     {$ENDC qDebug}
  812.  
  813.         if not pReserveExists then
  814.             begin
  815.                 pReserveExists := TRUE;                         { default value }
  816.  
  817.         { free the current code reserve }
  818.                 if HandleIsEligible(pCodeReserve) then
  819.                     EmptyHandle(pCodeReserve);
  820.  
  821.         { compute amt actually needed }
  822.                 needed := Min(pSzCodeReserve - TotalTempSize(FALSE, canPurge) - 8, allocLim);
  823.  
  824.                 if needed > 0 then
  825.                     begin
  826.             { make as much memory available as possible }
  827.                         if HandleIsEligible(pMemReserve) then
  828.                             EmptyHandle(pMemReserve);
  829.  
  830.                         if fromGZ then                                { Never purge or compact from GrowZone }
  831.                             avail := allocLim
  832.                         else
  833.                             begin
  834.                                 PurgeMem(needed);
  835.                                 avail := CompactMem(needed);
  836.                             end;
  837.  
  838.                         if avail < needed then                        { could not get the whole reserve }
  839.                             begin
  840.                 {$IFC qDebug}
  841.                                 pReserveShortfall := needed - avail;
  842.                 {$ENDC}
  843.  
  844.                                 pOKCodeReserve := FALSE;
  845.                                 pReserveExists := FALSE;
  846.  
  847.                                 needed := avail;                        { get the most we can }
  848.                             end;
  849.  
  850.                         if (not fromGZ) & (IsHandlePurged(pCodeReserve) | HandleIsEligible(pCodeReserve)) then
  851.                             ReallocHandle(pCodeReserve, needed);
  852.             {$IFC qDebug}
  853.                         theSize := GetHandleSize(pCodeReserve);
  854.             {$Push}
  855.  {$R-}
  856.                         if theSize <> 0 then
  857.                             BlockSet(pCodeReserve^, theSize, initVal);
  858.             {$Pop}
  859.             {$EndC}
  860.                         if not IsHandlePurged(pCodeReserve) then
  861.                             begin
  862.                 { Large handles are almost as bad as nonrelocatable blocks.}
  863. {                    Try to get this guy out of the way, just in case.}
  864.                                 if not fromGZ then
  865.                                     MoveHHi(pCodeReserve);
  866.                             end;
  867.                     end;
  868.             end;
  869.     end;
  870. {$Pop}
  871.  
  872. {--------------------------------------------------------------------------------------------------}
  873. {$S MAMemoryRes}
  874.  
  875.     function CheckReserve: BOOLEAN;
  876.  
  877.     begin
  878.         BuildAllReserves;
  879.         CheckReserve := pOKCodeReserve;
  880.     end;
  881.  
  882. {--------------------------------------------------------------------------------------------------}
  883. {$IFC qDebug}
  884. {$S MAMemoryRes}
  885.  
  886.     procedure CheckRsrcUsage;
  887.  
  888.         var
  889.             sz: LONGINT;
  890.             h: Handle;
  891.             s: Str255;
  892.  
  893.     begin
  894.         sz := TotalTempSize(TRUE, h);
  895.         if sz > gMaxLockedRsrc then
  896.             begin
  897.                 gMaxLockedRsrc := sz;
  898.                 if gRsrcReport then
  899.                     begin
  900.                         NumToString(gMaxLockedRsrc, s);
  901.                         s := Concat('  == New maximum resources usage: ', s, ' ==');
  902.                         ProgramReport(s, gMemMgtBreak);
  903.                     end;
  904.             end;
  905.     end;
  906. {$ENDC qDebug}
  907.  
  908. {--------------------------------------------------------------------------------------------------}
  909. {$IFC qDebug}
  910. {$S MADebug}
  911.  
  912.     procedure DoChangeReserve (alter: BOOLEAN; var codeReserve, codeShort, lowSpaceReserve: LONGINT; var gotCode, gotLowSpace: BOOLEAN);
  913.  
  914.         var
  915.             x: LONGINT;
  916.             s: Str255;
  917.  
  918.     begin
  919.         if alter then
  920.             begin
  921.                 Write('code reserve size = ', pSzCodeReserve : 1, '  ');
  922.                 if pOKCodeReserve then
  923.                     Writeln(' (OK)')
  924.                 else
  925.                     Writeln(' (gone)');
  926.  
  927.                 Write('low space reserve size = ', pSzMemReserve : 1, '  ');
  928.                 if not IsHandlePurged(pMemReserve) then
  929.                     Writeln(' (OK)')
  930.                 else
  931.                     Writeln(' (gone)');
  932.  
  933.                 Writeln;
  934.  
  935.                 Write('New code reserve (-1 = no change): ');
  936.                 Readln(x);
  937.                 if x >= 0 then
  938.                     codeReserve := x
  939.                 else
  940.                     codeReserve := pSzCodeReserve;
  941.  
  942.                 Write('New low space reserve (-1 = no change): ');
  943.                 Readln(x);
  944.                 if x >= 0 then
  945.                     lowSpaceReserve := x
  946.                 else
  947.                     lowSpaceReserve := pSzMemReserve;
  948.  
  949.                 Write('Reset max resource usage (Y or N) [N]? ');
  950.                 Readln(s);
  951.                 if s <> '' then
  952.                     if (s[1] = 'y') | (s[1] = 'Y') then
  953.                         begin
  954.                             gMaxLockedRsrc := 0;
  955.                         end;
  956.  
  957.                 Writeln;
  958.  
  959.                 SetReserveSize(codeReserve, lowSpaceReserve);
  960.             end
  961.         else
  962.             BuildAllReserves;
  963.  
  964.         codeReserve := pSzCodeReserve;
  965.         codeShort := pReserveShortfall;
  966.         lowSpaceReserve := pSzMemReserve;
  967.         gotCode := pOKCodeReserve;
  968.         gotLowSpace := not IsHandlePurged(pMemReserve);
  969.     end;
  970. {$ENDC qDebug}
  971.  
  972. {--------------------------------------------------------------------------------------------------}
  973. {$S MAMiniInit}
  974.  
  975.     procedure DoInitUMemory (var sizeTempReserve, sizeLowSpaceReserve: Size);
  976.  
  977.  { Called from InitUMemory so that InitUMemory can be in the main segment}
  978. {  and this code can be in another (unloadable) segment.}
  979.  
  980.         type
  981.             Mem = record                    { format of the mem! resource }
  982.                     codeVal, lowSpaceVal, stackVal: LONGINT;
  983.                 end;
  984.             MemPtr = ^Mem;
  985.             MemHandle = ^MemPtr;
  986.  
  987.         var
  988.             i: INTEGER;
  989.             oldResLoad: BOOLEAN;
  990.             seg: Handle;
  991.             StackTot: LONGINT;
  992.             h: Handle;
  993.             rsrcID: INTEGER;
  994.             rsrcType: ResType;
  995.             rsrcName: Str255;
  996.             lastRsrc: INTEGER;
  997.             mainSegment, utilitySegment: INTEGER;
  998.  
  999.     begin
  1000.     { Initialize memory management globals }
  1001.         pPermAllocation := FALSE;
  1002.         pMemReserve := NewHandle(0);
  1003.         FailNil(pMemReserve);
  1004.  
  1005.         pSzMemReserve := 0;
  1006.         pCodeReserve := NewHandle(0);
  1007.         FailNil(pCodeReserve);
  1008.  
  1009.         pSzCodeReserve := 0;
  1010.         gGZPurgeNotify := nil;
  1011.         pOKCodeReserve := TRUE;
  1012.         pReserveExists := FALSE;
  1013.     {$IFC qDebug}
  1014.         gSegReport := FALSE;
  1015.     {$EndC}
  1016.  
  1017.         gUnloadAllSegs := TRUE;
  1018.  
  1019.         gCodeRefNum := HomeResFile(GetResource(kCode, 1));    { Get homeresfile of "Main".}
  1020. {                                                        It better be there!!}
  1021.         pMaxSegNum := 0;
  1022.  
  1023.     {###########################################}
  1024.     { No resource loading }
  1025.  
  1026.         oldResLoad := GetResLoad;
  1027.         SetResLoad(FALSE);
  1028.  
  1029.     { Figure the highest segment number }
  1030.         if qNeedsROM128k | gConfiguration.hasROM128k then
  1031.             lastRsrc := MACount1Resources(kCode)
  1032.         else
  1033.             lastRsrc := MACountResources(kCode);
  1034.  
  1035.     { some development systems may not have contiguous numbering of CODE segments.}
  1036. {    try to be polite about handling it}
  1037.         for i := 1 to lastRsrc do
  1038.             begin
  1039.                 if qNeedsROM128k | gConfiguration.hasROM128k then
  1040.                     seg := MAGet1IndResource(kCode, i)
  1041.                 else
  1042.                     seg := MAGetIndResource(kCode, i);
  1043.         { we only have an index… find the real resource ID and keep track}
  1044. {        of the highest one}
  1045.                 if (seg <> nil) then
  1046.                     begin
  1047.                         GetResInfo(seg, rsrcID, rsrcType, rsrcName);
  1048.                         pMaxSegNum := Max(rsrcID, pMaxSegNum);
  1049.                     end;
  1050.             end;
  1051.  
  1052.  
  1053.         SetResLoad(oldResLoad); { in case of failure }
  1054.  
  1055.     { Allocate the master segment lists.}
  1056.         gCodeSegs := HandleListHandle(NewHandle(pMaxSegNum * SizeOf(Handle)));
  1057.         FailNil(gCodeSegs);
  1058.  
  1059.         gIsResidentSeg := BoolListHandle(NewHandle(SizeOf(BOOLEAN) * pMaxSegNum));
  1060.         FailNil(gIsResidentSeg);
  1061.  
  1062.         gIsLoadedSeg := BoolListHandle(NewHandle(SizeOf(BOOLEAN) * pMaxSegNum));
  1063.         FailNil(gIsLoadedSeg);
  1064.  
  1065.     { (NOTE: assumes application doesn't change the CODE segment size at runtime}
  1066. {    (a very safe assumption)). Used in GetSegFromPC.}
  1067.         pSegSize := LongListHandle(NewHandle(SizeOf(LONGINT) * pMaxSegNum));
  1068.         FailNil(pSegSize);
  1069.  
  1070.         oldResLoad := GetResLoad; { OK, suppress segment loading again }
  1071.         SetResLoad(FALSE);    { !!! Need an MAResLoad that returns old state }
  1072.  
  1073.     { Initialize segment lists.}
  1074.         for i := 1 to pMaxSegNum do
  1075.             gIsResidentSeg^^[i] := FALSE;
  1076.  
  1077.     { Segments and their sizes and actual loaded state (helps catch preloads) }
  1078.         for i := 1 to pMaxSegNum do
  1079.             begin
  1080.                 seg := GetSegResource(i);
  1081.                 gCodeSegs^^[i] := seg;
  1082.                 if seg <> nil then { seg is non-nil if the segment number exists }
  1083.                     begin
  1084.                         pSegSize^^[i] := SizeResource(seg);
  1085.                         gIsLoadedSeg^^[i] := IsHandleLocked(seg);
  1086.                     end
  1087.                 else
  1088.                     begin
  1089.                         pSegSize^^[i] := 0;
  1090.                         gIsLoadedSeg^^[i] := FALSE;
  1091.                     end;
  1092.             end;
  1093.  
  1094.         SetResLoad(oldResLoad);
  1095.     {###########################################}
  1096.  
  1097.         mainSegment := GetSegNumber(@InitUMemory);            { Main is always resident }
  1098.         gIsResidentSeg^^[mainSegment] := TRUE;
  1099.         gIsLoadedSeg^^[mainSegment] := TRUE;
  1100.  
  1101.         utilitySegment := GetSegNumber(@UnloadAllSegments); { Utilities are always resident }
  1102.         gIsResidentSeg^^[utilitySegment] := TRUE;
  1103.         gIsLoadedSeg^^[utilitySegment] := TRUE;
  1104.  
  1105.     { init the gSysMemList }
  1106.         gSysMemList := HandleListHandle(NewHandle(0));
  1107.         FailNil(gSysMemList);
  1108.  
  1109.         AddAllRsrc('LDEF', gSysMemList);
  1110.         AddAllRsrc('CDEF', gSysMemList);
  1111.         AddAllRsrc('MDEF', gSysMemList);
  1112.         AddAllRsrc('WDEF', gSysMemList);
  1113.         AddAllRsrc('PACK', gSysMemList);
  1114.  
  1115.     { Compute memory slop needed }
  1116.         sizeTempReserve := 0;
  1117.         sizeLowSpaceReserve := 0;
  1118.         StackTot := 0;
  1119.  
  1120.         for i := 1 to CountResources('seg!') do
  1121.             begin
  1122.                 h := GetIndResource('seg!', i);
  1123.                 sizeTempReserve := sizeTempReserve + AddSegSizes(h);
  1124.                 ReleaseResource(h);
  1125.             end;
  1126.  
  1127.         for i := 1 to CountResources('mem!') do
  1128.             begin
  1129.                 h := GetIndResource('mem!', i);
  1130.                 with MemHandle(h)^^ do
  1131.                     begin
  1132.                         sizeTempReserve := sizeTempReserve + codeVal;
  1133.                         sizeLowSpaceReserve := sizeLowSpaceReserve + lowSpaceVal;
  1134.                         StackTot := StackTot + stackVal;
  1135.                     end;
  1136.                 ReleaseResource(h);
  1137.             end;
  1138.  
  1139.         SetStackSpace(StackTot);
  1140.  
  1141.         MaxApplZone;
  1142.  
  1143.         gApp1MemList := nil;
  1144.         gApp2MemList := nil;
  1145.  
  1146.     end;
  1147.  
  1148. {--------------------------------------------------------------------------------------------------}
  1149. {$S MAMemoryRes}
  1150.  
  1151.     procedure FailNoReserve;
  1152.  
  1153.     begin
  1154.         if not CheckReserve then
  1155.             Failure(memFullErr, 0);
  1156.     end;
  1157.  
  1158. {--------------------------------------------------------------------------------------------------}
  1159. {$S MAMemoryRes}
  1160.  
  1161.     procedure FailSpaceIsLow;
  1162.  
  1163. {$IFC qDebug}
  1164.  
  1165.         var
  1166.             s: MAName;
  1167.         {$ENDC}
  1168.  
  1169.     begin
  1170.     {$IFC qDebug}
  1171.         if gAskFailure & CanReadLn then
  1172.             begin
  1173.                 GetCallersMethodName(s);
  1174.                 if ReadYesNo(Concat('FailSpaceIsLow called by ', s, '.  Return true(Y or N) [N]? ')) then
  1175.                     Failure(memFullErr, 0);
  1176.             end;
  1177.     {$ENDC}
  1178.  
  1179.         if MemSpaceIsLow then
  1180.             Failure(memFullErr, 0);
  1181.     end;
  1182.  
  1183. {--------------------------------------------------------------------------------------------------}
  1184. {$Push}
  1185.  {$IFC qTrace}
  1186.  {$N+}
  1187.  {$ENDC}
  1188. {$S MAMemoryRes}
  1189.  
  1190.     procedure GetReserveSize (var szCodeReserve, szMemReserve: Size);
  1191.  
  1192.     begin
  1193.         szCodeReserve := pSzCodeReserve;
  1194.         szMemReserve := pSzMemReserve;
  1195.     end;
  1196. {$Pop}
  1197.  
  1198. {--------------------------------------------------------------------------------------------------}
  1199. {$Push}
  1200.  {$IFC qTrace}
  1201.  {$N+}
  1202.  {$ENDC}
  1203.                      { no %_BP/%_EP allowed in here, because we}
  1204. {                                                         cannot call to any other segment from this}
  1205. {                                                         procedure}
  1206. {$S MAMemoryRes}
  1207.                                         { Shouldn't be unloaded }
  1208.  
  1209.     function GetSegFromPC (ppc: LONGINT): INTEGER;
  1210.  
  1211.         var
  1212.             pc: LONGINT;
  1213.             i: INTEGER;
  1214.             seg: Handle;
  1215.             segStart: LONGINT;
  1216.  
  1217.     begin
  1218.         pc := LongintPtr(ppc)^;
  1219.  
  1220.         GetSegFromPC := 0;                                    { default return }
  1221.  
  1222.     { Since GetSegFromPC may be called before gCodeSegs is set up, we have to test if gCodeSegs = NIL}
  1223. {    before using it.}
  1224.         if (gCodeSegs <> nil) then
  1225.             for i := 1 to pMaxSegNum do
  1226.                 begin
  1227.                     seg := gCodeSegs^^[i];                        { get segment handle }
  1228.                     if (seg <> nil) & not IsHandlePurged(seg) then { it's in memory }
  1229.                         begin
  1230.                             segStart := StripLong(seg^);            { get segment start }
  1231.                             if (pc >= segStart) & (pc < segStart + pSegSize^^[i]) then
  1232.                                 begin
  1233.                                     GetSegFromPC := i;
  1234.                                     LEAVE;
  1235.                                 end;
  1236.                         end;
  1237.                 end;
  1238.     end;
  1239. {$Pop}
  1240.  
  1241. {--------------------------------------------------------------------------------------------------}
  1242. {$Push}
  1243.  {$IFC qTrace}
  1244.  {$N+}
  1245.  {$ENDC}
  1246.                      { no %_BP/%_EP allowed in here, because we}
  1247. {                                                         cannot call to any other segment from this}
  1248. {                                                         procedure}
  1249. {$S MAMemoryRes}
  1250.                                         { must be in Main segment because we call}
  1251. {                                                         this in order to make the resident segment}
  1252. {                                                         resident}
  1253.  
  1254.     function GetSegNumber (aProc: ProcPtr): INTEGER;
  1255. { Gets seg number from a Jump table address }
  1256.  
  1257.         const
  1258.             kLoaded = $4EF9;                    { if loaded then a JMP instruction }
  1259.             kUnLoaded = $3F3C;                    { if unloaded then a LoadSeg trap }
  1260.  
  1261.         var
  1262.             i: INTEGER;
  1263.             jt: LONGINT;
  1264.             segNum: INTEGER;
  1265.             seg: Handle;
  1266.             segStart: LONGINT;
  1267.  
  1268.     begin
  1269.         if IntegerPtr(aProc)^ = kLoaded then                { loaded segment }
  1270.             GetSegNumber := IntegerPtr(Ord(aProc) - 2)^
  1271.         else if IntegerPtr(aProc)^ = kUnLoaded then         { unloaded segment }
  1272.             GetSegNumber := IntegerPtr(Ord(aProc) + 2)^
  1273.         else                                                { routine that computed @proc was in same}
  1274. {                                                         segment as the proc}
  1275.             begin
  1276.         {$IFC qDebug}
  1277.                 ProgramBreak('GetSegNumber was not passed an jump table address');
  1278.         {$ENDC}
  1279.                 GetSegNumber := 0;
  1280.             end;
  1281.     end;
  1282. {$Pop}
  1283.  
  1284. {--------------------------------------------------------------------------------------------------}
  1285. {$S MAMemoryRes}
  1286. {$Push}
  1287.  {$IFC qTrace}
  1288.  {$N+}
  1289.  {$ENDC}
  1290.  
  1291.     function GetSegSize (segNum: INTEGER): Size;
  1292.  
  1293.         var
  1294.             curResLoad: BOOLEAN;
  1295.             seg: Handle;
  1296.  
  1297.     begin
  1298.         GetSegSize := pSegSize^^[segNum];
  1299.     end;
  1300. {$Pop}
  1301.  
  1302. {--------------------------------------------------------------------------------------------------}
  1303. {$S MAMemoryRes}
  1304. {$Push}
  1305.  {$IFC qTrace}
  1306.  {$N+}
  1307.  {$ENDC}
  1308.  
  1309.     function GrowZoneProc (needed: Size): LONGINT;
  1310.  
  1311.         var
  1312.             result: LONGINT;
  1313.             canPurge: Handle;
  1314.             codeSize: Size;
  1315.             reserveSize: LONGINT;
  1316.             OldA5: LONGINT;
  1317.  
  1318.     begin
  1319.         OldA5 := SetCurrentA5;                                { Can be called from other worlds }
  1320.  
  1321.         result := 0;                                        { default is to fail }
  1322.  
  1323.         if not pDuringGrowZone then                            { prevent re-entrancy }
  1324.             begin
  1325.                 pDuringGrowZone := TRUE;
  1326.  
  1327.         { on a temp alloc, free all code slack immediately }
  1328.                 if not pPermAllocation & HandleIsEligible(pCodeReserve) then
  1329.                     begin
  1330.                         EmptyHandle(pCodeReserve);
  1331.                         pReserveExists := FALSE;
  1332.                         result := 1;
  1333.                     end;
  1334.  
  1335.                 if result = 0 then                                    { try harder: see if we can purge a code}
  1336. {                                                             segment or reduce the code reserve handle}
  1337. {}
  1338.                     begin
  1339.             { compute size of resources currently in memory }
  1340.  
  1341.                         codeSize := TotalTempSize(FALSE, canPurge);
  1342.  
  1343.             { see if the code reserve handle is too large }
  1344.  
  1345.                         if HandleIsEligible(pCodeReserve) then
  1346.                 { we have a code reserve handle; this implies permanent allocation,}
  1347. {                otherwise the handle would have been emptied above}
  1348.                             begin
  1349.                                 reserveSize := GetHandleSize(pCodeReserve);
  1350.  
  1351.                 { the following test is an optimization to avoid calling}
  1352. {                BuildCodeReserve if there is no hope of reducing}
  1353. {                the code reserve handle}
  1354.                                 if codeSize + reserveSize + 8 > pSzCodeReserve then
  1355.                                     begin                                    { reserve is too big }
  1356.                                         pReserveExists := FALSE;
  1357.                     { this should lower the code reserve }
  1358.                                         BuildCodeReserve(reserveSize, TRUE);
  1359.  
  1360.                     { see if we succeeded in freeing some memory }
  1361.                                         if IsHandlePurged(pCodeReserve) then
  1362.                                             result := 1
  1363.                                         else if GetHandleSize(pCodeReserve) < reserveSize then
  1364.                                             result := 1;
  1365.                                     end;
  1366.                             end;
  1367.  
  1368.                         if (result = 0) & (canPurge <> nil) & (not pPermAllocation | IsHandlePurged(pCodeReserve)) then           { got something; only purge it if this is}
  1369. {                                                             temporary OR we know there is too much}
  1370. {                                                             code in memory already}
  1371.                             begin
  1372.                                 if gGZPurgeNotify <> nil then
  1373.                                     CallNotify(canPurge, gGZPurgeNotify);
  1374.  
  1375.                                 reserveSize := GetHandleSize(canPurge);
  1376.                                 HPurge(canPurge);
  1377.                                 EmptyHandle(canPurge);
  1378.                                 pReserveExists := FALSE;
  1379.  
  1380.                                 if pPermAllocation then                     { don't free too much however }
  1381.                                     BuildCodeReserve(reserveSize, TRUE);
  1382.  
  1383.                                 result := 1;
  1384.                             end;
  1385.                     end;
  1386.  
  1387.                 if (result = 0) & HandleIsEligible(pMemReserve) then { last ditch attempt-free emergency}
  1388. {                                                              reserve}
  1389.                     begin
  1390.                         EmptyHandle(pMemReserve);
  1391.                         result := 1;
  1392.                     end;
  1393.  
  1394.                 pDuringGrowZone := FALSE;
  1395.             end;
  1396.  
  1397.         GrowZoneProc := result;
  1398.  
  1399.         OldA5 := SetA5(OldA5);
  1400.     end;
  1401. {$Pop}
  1402.  
  1403. {--------------------------------------------------------------------------------------------------}
  1404. {$S MAMemoryRes}
  1405. {$Push}
  1406.  {$IFC qTrace}
  1407.  {$N+}
  1408.  {$ENDC}
  1409.  
  1410.     function HandleIsEligible (h: Handle): BOOLEAN;
  1411.  
  1412.     begin
  1413.         if IsHandlePurged(h) then
  1414.             HandleIsEligible := FALSE
  1415.         else
  1416.             HandleIsEligible := (h <> GetGZMoveHnd) & (h <> GetGZRootHnd);
  1417.     end;
  1418. {$Pop}
  1419.  
  1420. {--------------------------------------------------------------------------------------------------}
  1421. {$S MAMemoryRes}
  1422.                                         { Must be in same segment as grow zone proc}
  1423. {}
  1424. {$Push}
  1425.  {$IFC qTrace}
  1426.  {$N+}
  1427.  {$ENDC}
  1428.  
  1429.     procedure InstallGrowZoneProc;
  1430. { Once called the grow zone proc's segment CANNOT be moved since we're passing a NON-JT address}
  1431. {to SetGrowZone (so we can be called from "other worlds"}
  1432.  
  1433.         var
  1434.             aZone: THz;
  1435.  
  1436.     begin
  1437.         aZone := ApplicZone;
  1438.         aZone^.flags := BOR(aZone^.flags, $0400);
  1439.   { set the Memory Manager bit that says to always call the}
  1440. {   Grow Zone proc, even in "non-critical" situations}
  1441.  
  1442.         pDuringGrowZone := FALSE;
  1443.  
  1444.         SetGrowZone(@GrowZoneProc);
  1445.  
  1446.     end;
  1447. {$Pop}
  1448.  
  1449. {--------------------------------------------------------------------------------------------------}
  1450. {$S Main}
  1451.                                                 { Must be in main segment and called from}
  1452. {                                                         main segment}
  1453.  
  1454.     procedure InitUMemory;
  1455.  
  1456.         var
  1457.             codeRes, lowSpaceRes: Size;
  1458.             miniInitSeg, utilitySeg: Handle;
  1459.             mainSeg: integer;
  1460.  
  1461.     begin
  1462.  
  1463.     { Get these segments out of the way so that when DoInitUMemory gets called and the next}
  1464. {    block of master pointers gets allocated they won't constipate the heap}
  1465.         miniInitSeg := GetResource(kCode, GetSegNumber(@DoInitUMemory));
  1466.         if miniInitSeg <> nil then
  1467.             begin
  1468.                 UnLoadSeg(@DoInitUMemory);
  1469.                 LockHandleHigh(miniInitSeg);
  1470.             end;
  1471.  
  1472.         DoInitUMemory(codeRes, lowSpaceRes);
  1473.  
  1474.         UnloadAllSegments;                                    { get init segment(s) out of middle of heap,}
  1475. {                                                         so SetReserveSize has maximum space to}
  1476. {                                                         work with}
  1477.  
  1478.         if miniInitSeg <> nil then                            { Yes, this would eventually get purged if}
  1479. {                                                         the space was needed badly enough, but}
  1480. {                                                         that happens very late in the game and can}
  1481. {                                                         confound the unwary}
  1482.             EmptyHandle(miniInitSeg);
  1483.  
  1484.         InstallGrowZoneProc;
  1485.  
  1486.         SetReserveSize(codeRes, lowSpaceRes);
  1487.         if not pOKCodeReserve then                            { couldn't get code reserve. Can't continue}
  1488. {}
  1489.             Failure(memFullErr, 0)
  1490.         else
  1491.     { Set up the LoadSeg patch }
  1492.  
  1493.             FailOSErr(PatchTrap(pSegLoadPatch, _LoadSeg, @ALoadMacAppSeg));
  1494.  
  1495.     end;
  1496.  
  1497. {--------------------------------------------------------------------------------------------------}
  1498. {$Push}
  1499.  {$IFC qTrace}
  1500.  {$N+}
  1501. {$D-}
  1502.  {$ENDC}
  1503.                      { no %_BP/%_EP allowed in here, because we}
  1504. {                                                         cannot call to any other segment from this}
  1505. {                                                         procedure}
  1506. {$S MAMemoryRes}
  1507.                                         { must be in Main segment }
  1508.  
  1509.     function LoadMacAppSegment (segNum: INTEGER): LONGINT;
  1510.  
  1511.         var
  1512.         {$IFC qDebug}
  1513.             id: INTEGER;
  1514.             kind: ResType;
  1515.             segName: Str255;
  1516.             s: MAName;
  1517.             seg: Handle;
  1518.         {$ENDC}
  1519.             A5RegisterOnEntry: LONGINT;
  1520.  
  1521.     begin
  1522.         A5RegisterOnEntry := SetCurrentA5;                    { ***** Called from trap patches *****}
  1523.  
  1524.         LoadMacAppSegment := pSegLoadPatch.oldTrapAddr;     { Where to go next }
  1525.  
  1526.         if GetA5 <> A5RegisterOnEntry then
  1527.             begin
  1528.         { not called from our application… don't do patch behaviour. Thank you McSink! }
  1529.                 pLoadSegCalledFromOwnApp := FALSE;
  1530.                 if SetA5(A5RegisterOnEntry) <> 0 then
  1531.                     ;
  1532.             end
  1533.         else
  1534.             begin
  1535.                 pLoadSegCalledFromOwnApp := TRUE;
  1536.                 pOldResFile := MAUseResFile(gCodeRefNum);        { Must set a global because we return from}
  1537. {                                                         this function and then forward to the}
  1538. {                                                         actual segment loader which should also be}
  1539. {                                                         pointing to the _now_ correct resfile.}
  1540. {                                                         When we get called back again in}
  1541. {                                                         PostLoadMacAppSegment we will restore the}
  1542. {                                                         old resFile as the current resFile. Sorry}
  1543. {                                                         about the global.}
  1544.  
  1545.         {$IFC qDebug}
  1546.                 if (ORD(GetResLoad) = 0) then
  1547.                     begin
  1548.                         SetResLoad(TRUE);
  1549.                         ProgramBreak('Whoops… LoadSeg called with resload set false');
  1550.                         Failure(minErr, 0);                         {??? Assign an error code someday or}
  1551. {                                                         setresload to TRUE ???}
  1552.                     end;
  1553.  
  1554.         {$ENDC}
  1555.  
  1556.                 if not PreloadSegmentResource(segNum) then
  1557.                     begin
  1558.             {$IFC qDebug}
  1559.                         GetCallersMethodName(s);
  1560.                         SetResLoad(FALSE);
  1561.                         if qNeedsROM128k | gConfiguration.hasROM128k then
  1562.                             seg := MAGet1Resource(kCode, segNum)
  1563.                         else
  1564.                             seg := MAGetResource(kCode, segNum);
  1565.                         GetResInfo(seg, id, kind, segName);
  1566.                         SetResLoad(TRUE);
  1567.                         ProgramBreak(Concat('In ', s, ConcatNumber(' couldn''t load segment: ', segNum), ' ', segName));
  1568.             {$ENDC}
  1569.                         Failure(memFullErr, 0)
  1570.                     end;
  1571.  
  1572.                 gIsLoadedSeg^^[segNum] := TRUE;
  1573.  
  1574.         {$IFC qDebug}
  1575.                 if gSegReport then
  1576.                     begin
  1577.             { Cause the debugger to break at the start of the next routine. }
  1578.                         gReportNext := TRUE;
  1579.                         GetResInfo(gCodeSegs^^[segNum], id, kind, segName);
  1580.                         gReportInfo := Concat(ConcatNumber('  *** Segment Loaded: ', segNum), ' ', segName);
  1581.                         gSingleStep := gMemMgtBreak;
  1582.                     end;
  1583.         {$ENDC}
  1584.  
  1585.             end;
  1586.     end;
  1587. {$Pop}
  1588.  
  1589. {--------------------------------------------------------------------------------------------------}
  1590. {$Push}
  1591.  {$IFC qTrace}
  1592.  {$N+}
  1593.  {$ENDC}
  1594.                      { no %_BP/%_EP allowed in here, because we}
  1595. {                                                         cannot call to any other segment from this}
  1596. {                                                         procedure}
  1597. {$Z+}
  1598. {$D-}
  1599. {$S MAMemoryRes}
  1600.                                         { must be in Main segment }
  1601.  
  1602.     procedure PostLoadMacAppSegment;
  1603.  
  1604.         var
  1605.             A5RegisterOnEntry: LONGINT;
  1606.  
  1607.     begin
  1608.         A5RegisterOnEntry := SetCurrentA5;                    { ***** Called from trap patches *****}
  1609.  
  1610.         if (GetA5 <> A5RegisterOnEntry) | not pLoadSegCalledFromOwnApp then
  1611.             begin
  1612.         { not called from our application… don't do patch behaviour. Thank you McSink! }
  1613.                 if SetA5(A5RegisterOnEntry) <> 0 then
  1614.                     ;
  1615.             end
  1616.         else
  1617.     { Called back from our glue.  Restores current res file pointer. }
  1618.             begin
  1619.                 if pLoadSegCalledFromOwnApp then
  1620.                     if MAUseResFile(pOldResFile) <> 0 then
  1621.                         ;
  1622.                 if SetA5(A5RegisterOnEntry) <> 0 then
  1623.                     ;
  1624.  
  1625.             end;
  1626.     end;
  1627. {$Pop}
  1628.  
  1629. {--------------------------------------------------------------------------------------------------}
  1630. {$S MAMemoryRes}
  1631.                                         { Must be in Main segment }
  1632.  
  1633.     procedure LoadResidentSegments;
  1634.  
  1635.         var
  1636.             resIndex: INTEGER;
  1637.             i: INTEGER;
  1638.             offset: INTEGER;
  1639.             nameList: Handle;
  1640.             segNumber: INTEGER;
  1641.             p: SignedBytePtr;
  1642.             name: Str255;
  1643.             seg: Handle;
  1644.             theType: ResType;
  1645.  
  1646.     begin
  1647.         for resIndex := 1 to CountResources('res!') do
  1648.             begin
  1649.                 nameList := GetIndResource('res!', resIndex);
  1650.                 HNoPurge(nameList);
  1651.  
  1652.                 offset := 2;
  1653.                 for i := 1 to IntegerPtr(nameList^)^ do
  1654.                     begin
  1655.                         p := SignedBytePtr(ORD4(nameList^) + offset);
  1656.                         BlockMove(Ptr(p), @name, p^ + 1);
  1657.                         offset := offset + LENGTH(name) + 1;
  1658.  
  1659.                         if qNeedsROM128k | gConfiguration.hasROM128k then
  1660.                             seg := MAGet1NamedResource(kCode, name)
  1661.                         else
  1662.                             seg := MAGetNamedResource(kCode, name);
  1663.                         if seg <> nil then
  1664.                             begin
  1665.                                 GetResInfo(seg, segNumber, theType, name);
  1666.                                 SetResidentSegment(segNumber, TRUE);
  1667.                             end;
  1668.                     end;
  1669.  
  1670.                 HPurge(nameList);
  1671.                 ReleaseResource(nameList);
  1672.             end;
  1673.     end;
  1674.  
  1675. {--------------------------------------------------------------------------------------------------}
  1676. {$S MAMemoryRes}
  1677.  
  1678.     function MemSpaceIsLow: BOOLEAN;
  1679.  
  1680.     begin
  1681.         BuildAllReserves;
  1682.  
  1683.         MemSpaceIsLow := IsHandlePurged(pMemReserve);
  1684.     end;
  1685.  
  1686. {--------------------------------------------------------------------------------------------------}
  1687. {$S MAMemoryRes}
  1688.  
  1689.     function NewPermHandle (logicalSize: Size): Handle;
  1690.  
  1691.         const
  1692.             initVal = $F3;                        { odd at all byte boundaries }
  1693.  
  1694.         var
  1695.             priorPerm: BOOLEAN;
  1696.         {$IFC qDebug}
  1697.             aHandle: Handle;
  1698.         {$EndC}
  1699.  
  1700.     begin
  1701.         priorPerm := PermAllocation(TRUE);
  1702.     {$IFC NOT qDebug}
  1703.         NewPermHandle := NewHandle(logicalSize);
  1704.     {$ELSEC}
  1705.         aHandle := NewHandle(logicalSize);
  1706.         NewPermHandle := aHandle;
  1707.     {$Push}
  1708.  {$R-}
  1709.         if aHandle <> nil then
  1710.             BlockSet(aHandle^, logicalSize, initVal);
  1711.     {$Pop}
  1712.     {$EndC}
  1713.         pPermAllocation := priorPerm;
  1714.     end;
  1715.  
  1716. {--------------------------------------------------------------------------------------------------}
  1717. {$S MAMemoryRes}
  1718.  
  1719.     function NewPermPtr (logicalSize: Size): Ptr;
  1720.  
  1721.         const
  1722.             initVal = $F5;                        { odd at all byte boundaries }
  1723.  
  1724.         var
  1725.             priorPerm: BOOLEAN;
  1726.         {$IFC qDebug}
  1727.             aPtr: Ptr;
  1728.         {$EndC}
  1729.  
  1730.     begin
  1731.         priorPerm := PermAllocation(TRUE);
  1732.     {$IFC NOT qDebug}
  1733.         NewPermPtr := NewPtr(logicalSize);
  1734.     {$ELSEC}
  1735.         aPtr := NewPtr(logicalSize);
  1736.         NewPermPtr := aPtr;
  1737.     {$Push}
  1738.  {$R-}
  1739.         if aPtr <> nil then
  1740.             BlockSet(aPtr, logicalSize, initVal);
  1741.     {$Pop}
  1742.     {$EndC}
  1743.         pPermAllocation := priorPerm;
  1744.     end;
  1745.  
  1746. {--------------------------------------------------------------------------------------------------}
  1747. {$Push}
  1748.  {$IFC qTrace}
  1749.  {$N+}
  1750.  {$ENDC}
  1751. {$S MAMemoryRes}
  1752.  
  1753.     function PermAllocation (permanent: BOOLEAN): BOOLEAN;
  1754.  
  1755.         var
  1756.             b: BOOLEAN;
  1757.  
  1758.     begin
  1759.         PermAllocation := pPermAllocation;
  1760.  
  1761.         if permanent <> pPermAllocation then
  1762.             begin
  1763.                 pPermAllocation := permanent;
  1764.  
  1765.                 if permanent then
  1766.                     BuildCodeReserve(kGZMaxAlloc, FALSE);
  1767.             end;
  1768.     end;
  1769. {$Pop}
  1770.  
  1771. {--------------------------------------------------------------------------------------------------}
  1772. {$Push}
  1773.  {$IFC qTrace}
  1774.  {$N+}
  1775.  {$D-}
  1776. {$ENDC}
  1777.                      { no %_BP/%_EP allowed in here, because we}
  1778. {                                                         cannot call to any other segment from this}
  1779. {                                                         procedure}
  1780. {$S MAMemoryRes}
  1781.                                         { must be in Main segment }
  1782.  
  1783.     function PreloadSegmentResource (segNum: INTEGER): BOOLEAN;
  1784.  
  1785.         var
  1786.             seg: Handle;
  1787.             err: OSErr;
  1788.  
  1789.         procedure DoGetSegHandle;
  1790.  
  1791.         begin
  1792.             if qNeedsROM128k | gConfiguration.hasROM128k then
  1793.                 seg := Get1Resource(kCode, segNum)
  1794.             else
  1795.                 seg := GetResource(kCode, segNum);
  1796.         end;
  1797.  
  1798.     begin
  1799.         if qDebug & pPermAllocation then
  1800.             begin
  1801.                 Writeln('segment # = ', segNum : 1);
  1802.                 ProgramBreak('Trying to load a segment with PermAllocation = TRUE.');
  1803.             end;
  1804.  
  1805.         WithCodeResFileDo(DoGetSegHandle);
  1806.  
  1807.         if seg = nil then
  1808.             PreloadSegmentResource := FALSE
  1809.         else
  1810.             begin
  1811.                 PreloadSegmentResource := TRUE;
  1812.  
  1813.                 if not IsHandleLocked(seg) then                 { not yet locked }
  1814.                     LockHandleHigh(seg);
  1815.             end;
  1816.     end;
  1817.  
  1818. {--------------------------------------------------------------------------------------------------}
  1819. {$S MAMemoryRes}
  1820.  
  1821.     procedure RemHandle (h: Handle; toList: HandleListHandle);
  1822.  
  1823.         var
  1824.             p: LONGINT;
  1825.             maxP: LONGINT;
  1826.             offset: LONGINT;
  1827.  
  1828.     begin
  1829.         p := Ord(toList^);                                    { Address of first element }
  1830.         maxP := p + GetHandleSize(Handle(toList));            { Address past last element }
  1831.  
  1832.     { Skip elements until item is found }
  1833.         while (p < maxP) & (LongintPtr(p)^ <> Ord(h)) do
  1834.             p := p + SizeOf(Handle);
  1835.  
  1836.         if p < maxP then                                    { Item was found }
  1837.             begin
  1838.                 offset := Munger(Handle(toList), p - Ord(toList^), nil, SizeOf(Handle), @h, 0);
  1839.                 FailMemError;
  1840.             end;
  1841.     end;
  1842.  
  1843. {--------------------------------------------------------------------------------------------------}
  1844. {$S MAMemoryRes}
  1845. {$Push}
  1846.  {$IFC qTrace}
  1847.  {$N+}
  1848.  {$ENDC}
  1849.  
  1850.     procedure ScanHandles (procedure DoToHandle (h: Handle));
  1851.  
  1852.         procedure ScanList (list: HandleListHandle);
  1853.  
  1854.             type
  1855.                 HandlePtr = ^Handle;
  1856.  
  1857.             var
  1858.                 i: INTEGER;
  1859.                 p: HandlePtr;
  1860.  
  1861.         begin
  1862.             i := GetHandleSize(Handle(list)) div SizeOf(Handle);
  1863.  
  1864.             p := HandlePtr(list^);
  1865.             while i > 0 do
  1866.                 begin
  1867.                     DoToHandle(p^);
  1868.                     p := HandlePtr(Ord(p) + SizeOf(Handle));
  1869.                     i := i - 1;
  1870.                 end;
  1871.         end;
  1872.  
  1873.     begin
  1874.         ScanList(gCodeSegs);
  1875.         if gApp1MemList <> nil then
  1876.             ScanList(gApp1MemList);
  1877.         ScanList(gSysMemList);
  1878.         if gApp2MemList <> nil then
  1879.             ScanList(gApp2MemList);
  1880.     end;
  1881. {$Pop}
  1882.  
  1883. {--------------------------------------------------------------------------------------------------}
  1884. {$S MAMemoryRes}
  1885.  
  1886.     procedure SetPermHandleSize (h: Handle; newSize: Size);
  1887.  
  1888.         const
  1889.             initVal = $F3;                        { odd at all byte boundaries }
  1890.  
  1891.         var
  1892.             priorPerm: BOOLEAN;
  1893.         {$IFC qDebug}
  1894.             oldSize: Size;
  1895.         {$EndC}
  1896.  
  1897.     begin
  1898.         priorPerm := PermAllocation(TRUE);
  1899.     {$IFC qDebug}
  1900.         oldSize := GetHandleSize(h);
  1901.     {$EndC}
  1902.         SetHandleSize(h, newSize);
  1903.         pPermAllocation := priorPerm;                        { Since we are in the memory unit we can}
  1904. {                                                         break the encapsulation of the}
  1905. {                                                         PermAllocation Call to just set the}
  1906. {                                                         pPermAllocation flag back directly. This}
  1907. {                                                         lets us be assured that no operations have}
  1908. {                                                         occurred that would invalidate the MemErr}
  1909. {                                                         flag… thus the following call will give a}
  1910. {                                                         true result}
  1911.         FailMemError;
  1912.     {$IFC qDebug}
  1913.     {$Push}
  1914.  {$R-}
  1915.         if oldSize < newSize then
  1916.             BlockSet(Ptr(Ord(h^) + oldSize), newSize - oldSize, initVal);
  1917.     {$Pop}
  1918.     {$EndC}
  1919.     end;
  1920.  
  1921. {--------------------------------------------------------------------------------------------------}
  1922. {$S MAMemoryRes}
  1923.  
  1924.     procedure SetPermPtrSize (p: Ptr; newSize: Size);
  1925.  
  1926.         const
  1927.             initVal = $F5;                        { odd at all byte boundaries }
  1928.  
  1929.         var
  1930.             priorPerm: BOOLEAN;
  1931.         {$IFC qDebug}
  1932.             oldSize: Size;
  1933.         {$EndC}
  1934.  
  1935.     begin
  1936.         priorPerm := PermAllocation(TRUE);
  1937.     {$IFC qDebug}
  1938.         oldSize := GetPtrSize(p);
  1939.     {$EndC}
  1940.         SetPtrSize(p, newSize);
  1941.         pPermAllocation := priorPerm;                        { Since we are in the memory unit we can}
  1942. {                                                         break the encapsulation of the}
  1943. {                                                         PermAllocation Call to just set the}
  1944. {                                                         pPermAllocation flag back directly. This}
  1945. {                                                         lets us be assured that no operations have}
  1946. {                                                         occurred that would invalidate the MemErr}
  1947. {                                                         flag… thus the following call will give a}
  1948. {                                                         true result}
  1949.         FailMemError;
  1950.     {$IFC qDebug}
  1951.     {$Push}
  1952.  {$R-}
  1953.         if oldSize < newSize then
  1954.             BlockSet(Ptr(Ord(p) + oldSize), newSize - oldSize, initVal);
  1955.     {$Pop}
  1956.     {$EndC}
  1957.     end;
  1958.  
  1959. {--------------------------------------------------------------------------------------------------}
  1960. {$S MAMemoryRes}
  1961.  
  1962.     procedure SetReserveSize (forCode, forOther: Size);
  1963.  
  1964.         var
  1965.             oldPerm: BOOLEAN;
  1966.  
  1967.     begin
  1968.         pSzCodeReserve := forCode;
  1969.         pSzMemReserve := forOther;
  1970.  
  1971.     { Since the numbers have changed, make sure we start from scratch. }
  1972.         pReserveExists := FALSE;
  1973.         EmptyHandle(pMemReserve);
  1974.  
  1975.         BuildAllReserves;
  1976.     end;
  1977.  
  1978. {--------------------------------------------------------------------------------------------------}
  1979. {$Push}
  1980.  {$IFC qTrace}
  1981.  {$N+}
  1982.  {$ENDC}
  1983.                      { no %_BP/%_EP allowed in here, because we}
  1984. {                                                         cannot call to any other segment from this}
  1985. {                                                         procedure}
  1986. {$S MAMemoryRes}
  1987.                                         { must be in Main segment }
  1988.  
  1989.     procedure SetResidentSegment (segNum: INTEGER; makeResident: BOOLEAN);
  1990.  
  1991.         var
  1992.         {$IFC qDebug}
  1993.             id: INTEGER;
  1994.             kind: ResType;
  1995.             segName: Str255;
  1996.             s: MAName;
  1997.         {$ENDC}
  1998.             seg: Handle;
  1999.  
  2000.     begin
  2001.         if makeResident then
  2002.             begin
  2003.                 gIsResidentSeg^^[segNum] := TRUE;
  2004.                 if not PreloadSegment(segNum) then
  2005.                     begin
  2006.             {$IFC qDebug}
  2007.                         GetCallersMethodName(s);
  2008.                         SetResLoad(FALSE);
  2009.                         if qNeedsROM128k | gConfiguration.hasROM128k then
  2010.                             seg := MAGet1Resource(kCode, segNum)
  2011.                         else
  2012.                             seg := MAGetResource(kCode, segNum);
  2013.                         SetResLoad(TRUE);
  2014.                         GetResInfo(seg, id, kind, segName);
  2015.                         ProgramBreak(Concat('In ', s, ConcatNumber(' couldn''t load segment: ', segNum), ' ', segName));
  2016.             {$ENDC}
  2017.                         Failure(memFullErr, 0)
  2018.                     end
  2019.             end
  2020.         else
  2021.             begin
  2022.                 gIsResidentSeg^^[segNum] := FALSE;
  2023.             end;
  2024.     end;
  2025. {$Pop}
  2026.  
  2027. {--------------------------------------------------------------------------------------------------}
  2028. {$S MAMiniInit}
  2029.  
  2030.     procedure SetStackSpace (numBytes: LONGINT);
  2031.  
  2032.         var
  2033.             curLimit: LONGINT;
  2034.             newLimit: LONGINT;
  2035.  
  2036.     begin
  2037.         newLimit := Ord(GetCurStackBase) - numBytes;
  2038.  
  2039.         if Ord(GetApplLimit) > newLimit then
  2040.             SetApplLimit(Ptr(newLimit));
  2041.     end;
  2042.  
  2043. {--------------------------------------------------------------------------------------------------}
  2044. {$S MAMemoryRes}
  2045. {$Push}
  2046.  {$IFC qTrace}
  2047.  {$N+}
  2048.  {$ENDC}
  2049.  
  2050.     function TotalTempSize (justLocked: BOOLEAN; var canPurge: Handle): Size;
  2051.  
  2052.         var
  2053.             total: Size;
  2054.             applZone: THz;
  2055.  
  2056.         procedure TotalUp (h: Handle);
  2057.  
  2058.             var
  2059.                 hIsLocked: BOOLEAN;
  2060.  
  2061.         begin
  2062.             if not IsHandlePurged(h) then                    { in memory already }
  2063.                 if HandleZone(h) = applZone then            { in application heap }
  2064.                     begin
  2065.                         HNoPurge(h);
  2066.  
  2067.                         hIsLocked := IsHandleLocked(h);
  2068.  
  2069.                         if not justLocked | hIsLocked then
  2070.                             total := total + GetHandleSize(h) + 8;
  2071.                 { add in the size plus heap overhead }
  2072.  
  2073.                         if not hIsLocked then
  2074.                             if canPurge = nil then
  2075.                                 if HandleIsEligible(h) then
  2076.                                     canPurge := h;
  2077.                     end;
  2078.         end;
  2079.  
  2080.     begin
  2081.         canPurge := nil;
  2082.         total := 0;
  2083.         applZone := ApplicZone;
  2084.  
  2085.         ScanHandles(TotalUp);
  2086.  
  2087.         TotalTempSize := total;
  2088.     end;
  2089. {$Pop}
  2090.  
  2091. {--------------------------------------------------------------------------------------------------}
  2092. {$S MAMemoryRes}
  2093. {$Push}
  2094.  {$IFC qTrace}
  2095.  {$N+}
  2096.  {$ENDC}
  2097.  
  2098.     procedure WithCodeResFileDo (procedure DoWithResFile);
  2099.  
  2100.         var
  2101.             oldResFile: INTEGER;
  2102.  
  2103.     begin
  2104.         oldResFile := MAUseResFile(gCodeRefNum);
  2105.         DoWithResFile;
  2106.         if MAUseResFile(oldResFile) <> 0 then
  2107.             ;
  2108.     end;
  2109. {$Pop}
  2110.  
  2111. {--------------------------------------------------------------------------------------------------}
  2112. {$Push}
  2113.  {$IFC qTrace}
  2114.  {$N+}
  2115.  {$ENDC}
  2116.                      { no %_BP/%_EP allowed in here, because we}
  2117. {                                                         cannot call to any other segment from this}
  2118. {                                                         procedure}
  2119. {$S MAMemoryRes}
  2120.                                         { must be in Main segment }
  2121.  
  2122.     procedure UnloadAllSegments;
  2123.  
  2124.         var
  2125.             i: LONGINT;
  2126.             seg: Handle;
  2127.             jumpTablePtr: LONGINT;
  2128.             oldResLoad: BOOLEAN;
  2129.  
  2130.         procedure DoToFrame (calleeFrame: LONGINT; ppc: LONGINT; callerFrame: LONGINT; itsFrame: LONGINT);
  2131.  
  2132.             var
  2133.                 seg: INTEGER;
  2134.  
  2135.         begin
  2136.             seg := GetSegFromPC(ppc);
  2137.             if (seg <> 0) & not gIsResidentSeg^^[seg] & gIsLoadedSeg^^[seg] then
  2138.                 begin
  2139.                     Writeln('Segment#: ', seg : 2);
  2140.                     ProgramBreak('I really don''t think that you want to unload a segment into which you are going to return!')
  2141.                 end;
  2142.         end;
  2143.  
  2144.         procedure UnloadEm;
  2145.  
  2146.             var
  2147.                 i: integer;
  2148.  
  2149.         begin
  2150.             for i := 1 to pMaxSegNum do
  2151.                 if not gIsResidentSeg^^[i] & gIsLoadedSeg^^[i] then
  2152.                     begin
  2153.                         seg := gCodeSegs^^[i];
  2154.                         if (seg <> nil) & not IsHandlePurged(seg) then
  2155.                             begin
  2156. {$IFC NOT OPTION(FarCode)}
  2157.                                 UnLoadSeg(Ptr(jumpTablePtr + IntegerHandle(seg)^^ + 2));
  2158. {$ELSEC}
  2159.                                 UnLoadSeg(Ptr(jumpTablePtr + (Ord4(IntegerHandle(seg)^^) * 8) + 2));
  2160. {$ENDC}
  2161.                                 gIsLoadedSeg^^[i] := FALSE;
  2162.                             end;
  2163.                     end;
  2164.         end;
  2165.  
  2166.     begin
  2167.     {$IFC qDebug}
  2168.         CheckRsrcUsage;
  2169.     {$ENDC}
  2170.  
  2171.         if gUnloadAllSegs then
  2172.             begin
  2173.                 jumpTablePtr := Ord(GetA5) + GetCurJTOffset;
  2174.  
  2175.         {$IFC qDebug}
  2176.                 EachFrameDo(Ord(GetCurStackFramePtr), Ord(GetCurStackFramePtr) + 4, DoToFrame);
  2177.         {$EndC}
  2178.  
  2179.                 WithCodeResFileDo(UnloadEm);
  2180.  
  2181.         {$IFC qDebug}
  2182.                 if gSegReport then
  2183.                     ProgramReport('  *** Just unloaded all segments ***', gMemMgtBreak);
  2184.         {$ENDC}
  2185.             end;
  2186.     end;
  2187. {$Pop}
  2188.  
  2189. {--------------------------------------------------------------------------------------------------}
  2190. {$IFC qDebug}
  2191. {$S MADebug}
  2192.  
  2193.     procedure WriteReserves;
  2194.  
  2195. { WRITELN's the temporary reserve and low-memory reserves in the}
  2196. {debug window.}
  2197.  
  2198.     begin
  2199.         WrLblPtr('Temporary reserve (pCodeReserve)', pCodeReserve);
  2200.         Writeln;
  2201.         WrLblPtr('Low-memory reserve (pMemReserve)', pMemReserve);
  2202.         Writeln;
  2203.     end;
  2204. {$ENDC}
  2205.  
  2206.  
  2207. end.